package com.wh.wisdomsite.xbox.utils.server;

import java.io.*;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import com.wh.wisdomsite.xbox.utils.date.DateTool;
import com.wh.wisdomsite.xbox.utils.random.RandomTool;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.pool.PoolStats;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EntityUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * 采用HttpClient连接服务器进行数据通讯(采用CloseableHttpClient抽象类实现HttpClient接口)
 * @Package com.wh.wisdomsite.xbox.utils.server
 * @author 谢泽鹏
 * @date 2014年10月14日 下午2:10:42
 * @Copyright 个人版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2014
 * @version V1.0
 */
public class connToserver_HttpClientClose {


    private static final Log logger = LogFactory.getLog(connToserver_HttpClientClose.class);


    private static PoolingHttpClientConnectionManager connManager = null;

    private static CloseableHttpClient httpClient = null;


    static {
        //获取SocketFactory链接工厂
        ConnectionSocketFactory connectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
        //创建SSLScoket工厂
        LayeredConnectionSocketFactory layeredConnectionSocketFactory = createSSLConnSocketFactory();
        //注册http和https协议支持
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", connectionSocketFactory)
                .register("https", layeredConnectionSocketFactory).build();
        //创建链接管理器
        connManager = new PoolingHttpClientConnectionManager(registry);


        //设置链接管理器最大链接数(200)
        connManager.setMaxTotal(connToserver_Setting.CONNECTION_TOTAL);
        //设置默认最大路由数(400)
        connManager.setDefaultMaxPerRoute(connToserver_Setting.MAX_ROUTE_CONNECTIONS);
        //设置可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间，如果超过，释放socket重新建立(30秒)
        connManager.setValidateAfterInactivity(30 * 1000);

        //创建SocketConfig对象
        SocketConfig socketConfig = SocketConfig.custom()
                //设置socket传输超时时间(10秒)
                .setSoTimeout(connToserver_Setting.SOCKET_TIMEOUT)
                //设置保持链接(true)
                .setSoKeepAlive(true)
                //设置发送数据流缓冲区大小(1024 * 8)
                .setSndBufSize(connToserver_Setting.BUFFERSIZE)
                //设置读取数据流缓冲区大小(1024 * 8)
                .setRcvBufSize(connToserver_Setting.BUFFERSIZE)
                .build();
        //设置SocketConfig对象
        connManager.setDefaultSocketConfig(socketConfig);

        //创建RequestConfig对象
        RequestConfig requestConfig = RequestConfig.custom()
                //设置链接请求超时时间(10秒)
                .setConnectionRequestTimeout(connToserver_Setting.REQUEST_TIMEOUT)
                //设置链接超时时间(10秒)
                .setConnectTimeout(connToserver_Setting.CONNECTION_TIMEOUT)
                 //设置链接传输超时时间(10秒)
                .setSocketTimeout(connToserver_Setting.SOCKET_TIMEOUT)
                .build();

        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                //如果已经重试了3次，就放弃
                if (executionCount >= 3) {
                    return false;
                }
                //如果服务器丢掉了连接，那么就重试
                if (exception instanceof NoHttpResponseException) {
                    return true;
                }
                //不要重试SSL握手异常
                if (exception instanceof SSLHandshakeException) {
                    return false;
                }
                //超时
                if (exception instanceof InterruptedIOException) {
                    return true;
                }
                //目标服务器不可达
                if (exception instanceof UnknownHostException) {
                    return false;
                }
                //连接被拒绝
                if (exception instanceof ConnectTimeoutException) {
                    return false;
                }
                //ssl握手异常
                if (exception instanceof SSLException) {
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                //如果请求是幂等的，就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };

        httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).build();
        if (connManager != null && connManager.getTotalStats() != null) {
            logger.info("now client pool " + connManager.getTotalStats().toString());
        }
    }


    /**
     * 创建SSL链接工厂
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        //声明链接工厂
        SSLConnectionSocketFactory sslConnectionSocketFactory = null;
        //声明SSLContext上下文
        SSLContext sslContext;
        try {
            X509TrustManager trustManager = new X509TrustManager() {

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String authType) throws CertificateException {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String authType) throws CertificateException {

                }
            };
            //创建sslContext对象
            sslContext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            //初始化sslContext对象
            sslContext.init(null, new TrustManager[] {(TrustManager) trustManager}, null);
            //创建SSLSocketFactory
            sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("构建ScoketFactory异常 " + e.getMessage());
        }
        return sslConnectionSocketFactory;
    }


    /**
     * 创建CloseableHttpClient链接工厂
     * @return
     */
    public static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
            httpClient = HttpClients.createDefault();
            logger.error("构建CloseableHttpClient异常 SSLUtilsErrorKetManage： " + e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            httpClient = HttpClients.createDefault();
            logger.error("构建CloseableHttpClient异常 SSLUtilsErrorNOAlgorithm： " + e.getMessage());
        } catch (KeyStoreException e) {
            e.printStackTrace();
            httpClient = HttpClients.createDefault();
            logger.error("构建CloseableHttpClient异常 KeyStoreException： " + e.getMessage());
        }
            return httpClient;

    }


    /**
     * 发送get请求(远程主机响应正文)
     * @see 1)该方法会自动关闭连接,释放资源
     * @see 2)方法内设置了连接和读取超时时间,单位为毫秒
     * @see 3)请求参数含中文时,经测试可直接传入中文,HttpClient会自动编码发给Server,应用时应根据实际效果决定传入前是否转码
     * @see 4)该方法会自动获取到响应消息头中[Content-Type:text/html; charset=GBK]的charset值作为响应报文的解码字符集
     * @see 5)若响应消息头中无Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1作为响应报文的解码字符集
     * @param url 请求地址(含参数)
     * @return
     */
    public static String sendGetRequest(String url, Map<String, String> map) throws Exception {
        //响应内容
        String result = null;
        //错误消息
        String errorMsg = null;
        //声明响应
        CloseableHttpResponse httpResponse = null;
        //声明HttpGet
        HttpGet httpget = null;
        try {
            String urlName = null;
            StringBuilder sb = new StringBuilder();
            if(null == map){
                //获取请求地址
                urlName = url;
            }
            if (null != map && !map.isEmpty()) {
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    sb.append(entry.getKey()).append("=");
                    sb.append(URLEncoder.encode(entry.getValue(), connToserver_Setting.REQUEST_ENCONEING));
                    sb.append("&");
                }
                sb.deleteCharAt(sb.length() - 1);
                //获取请求参数
                String params = sb.toString();
                //获取请求地址
                urlName = url + "?" + params;
            }
            logger.info("请求URL地址：" + urlName);
            logger.info("请求参数信息：" + map);
            //创建HttpGet
            httpget = new HttpGet(urlName);
            //执行get请求
            httpResponse = httpClient.execute(httpget, HttpClientContext.create());
            //获取响应实体
            HttpEntity entity = httpResponse.getEntity();
            if (null != entity) {
                Charset respCharset = ContentType.getOrDefault(entity).getCharset();
                result = EntityUtils.toString(entity, respCharset);
                EntityUtils.consume(entity);
            }
        } catch (ConnectTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时连接超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (SocketTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时读取超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ClientProtocolException e) {
            errorMsg = "请求通信[" + url + "]时协议异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ParseException e) {
            errorMsg = "请求通信[" + url + "]时解析异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (IOException e) {
            errorMsg = "请求通信[" + url + "]时网络异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (Exception e) {
            errorMsg = "请求通信[" + url + "]时偶遇异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } finally {
            //释放资源
            releaseResources(httpResponse, httpget, errorMsg, url);
        }
            return result;
    }


    /**
     * 重构sendPostRequest
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public static String sendPostRequest(String url, Map<String, String> map) throws Exception {
        return sendPostRequest(url, map, null);
    }

    /**
     * 发送POST请求(远程主机响应正文)
     * @see 1)该方法允许自定义任何格式和内容的HTTP请求报文体
     * @see 2)该方法会自动关闭连接,释放资源
     * @see 3)方法内设置了连接和读取超时时间,单位为毫秒,超时或发生其它异常时方法会自动返回"通信失败"字符串
     * @see 4)请求参数含中文等特殊字符时,可直接传入本方法,并指明其编码字符集encodeCharset参数,方法内部会自动对其转码
     * @see 5)该方法在解码响应报文时所采用的编码,取自响应消息头中的[Content-Type:text/html; charset=GBK]的charset值若响应消息头中未指定Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1
     * @param url 请求地址
     * @param map 请求参数
     */
    public static String sendPostRequest(String url, Map<String, String> map, File[] files) throws Exception {
        //响应内容
        String result = null;
        //错误消息
        String errorMsg = null;
        //声明响应
        CloseableHttpResponse httpResponse = null;
        //声明HttpPost
        HttpPost httpPost = null;
        try {
            logger.info("请求URL地址：" + url);
            logger.info("请求参数信息：" + map);
            //创建HttpPost对象
            httpPost = new HttpPost(url);
            //构建参数对象
            List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
            //定义httpEntity
            HttpEntity httpEntity = null;
            if (null != files && files.length > 0) {
                MultipartEntityBuilder meb = MultipartEntityBuilder.create();
                //设置兼容浏览器
                meb.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
                //设置字符集 utf-8
                meb.setCharset(CharsetUtils.get(connToserver_Setting.REQUEST_ENCONEING));
               for (File file : files) {
                    //转换成FileBody
                    FileBody fileBody = new FileBody(file);
                    meb.addPart("upload", fileBody);
                }
                if (null != map && map.size() > 0) {
                    ContentType contentType= ContentType.create("text/plain", connToserver_Setting.REQUEST_ENCONEING);
                    for (String key : map.keySet()) {
                        //封装参数
                        StringBody comment = new StringBody(map.get(key), contentType);
                        meb.addPart(key, comment);
                    }
                }
                httpEntity = meb.build();
            } else {
                //设置Header
                httpPost.setHeader("accept", "application/json; charset=" + connToserver_Setting.REQUEST_ENCONEING);
                httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + connToserver_Setting.REQUEST_ENCONEING);
                // 创建参数列表
                if (null != map && !map.isEmpty()) {
                    for (Map.Entry<String, String> entry : map.entrySet()) {
                        paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                    }
                }
                    httpEntity = new UrlEncodedFormEntity(paramsList, "UTF-8");
            }
            //设置entity报文信息
            httpPost.setEntity(httpEntity);
            //获取响应
            httpResponse = httpClient.execute(httpPost, HttpClientContext.create());
            HttpEntity entity = httpResponse.getEntity();
            if (null != entity) {
                result = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
                EntityUtils.consume(entity);
            }
        } catch (UnsupportedEncodingException e){
            errorMsg = "请求通信[" + url + "]字符集转换,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ConnectTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时连接超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (SocketTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时读取超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ClientProtocolException e) {
            errorMsg = "请求通信[" + url + "]时协议异常,堆栈信息如下:" + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ParseException e) {
            errorMsg = "请求通信[" + url + "]时解析异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (IOException e) {
            errorMsg = "请求通信[" + url + "]时网络异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (Exception e) {
            errorMsg = "请求通信[" + url + "]时网络异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } finally {
            //释放资源
            releaseResources(httpResponse, httpPost, errorMsg, url);
        }
        return result;
    }


    /**
     * 发送POST请求(远程主机响应正文)
     * @see 1)该方法允许自定义任何格式和内容的HTTP请求报文体
     * @see 2)该方法会自动关闭连接,释放资源
     * @see 3)方法内设置了连接和读取超时时间,单位为毫秒,超时或发生其它异常时方法会自动返回"通信失败"字符串
     * @see 4)请求参数含中文等特殊字符时,可直接传入本方法,并指明其编码字符集encodeCharset参数,方法内部会自动对其转码
     * @see 5)该方法在解码响应报文时所采用的编码,取自响应消息头中的[Content-Type:text/html; charset=GBK]的charset值若响应消息头中未指定Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1
     * @param url 请求地址
     * @param map 请求参数
     */
    public static String sendPostRequest(String url, String path, Map<String, String> map) throws Exception {
        String fileName = "";
        //错误消息
        String errorMsg = null;
        //声明响应
        CloseableHttpResponse httpResponse = null;
        //声明HttpPost
        HttpPost httpPost = null;
        try {
            logger.info("请求URL地址：" + url);
            logger.info("请求参数信息：" + map);
            //创建HttpPost对象
            httpPost = new HttpPost(url);
            //构建参数对象
            List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
            httpPost.setHeader("accept", "application/json; charset=" + connToserver_Setting.REQUEST_ENCONEING);
            httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + connToserver_Setting.REQUEST_ENCONEING);
            // 创建参数列表
            if (null != map && !map.isEmpty()) {
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            HttpEntity httpEntity = new UrlEncodedFormEntity(paramsList, "UTF-8");
            //设置entity报文信息
            httpPost.setEntity(httpEntity);
            //获取响应
            httpResponse = httpClient.execute(httpPost, HttpClientContext.create());
            HttpEntity entity = httpResponse.getEntity();
            if (null != entity) {
                byte[] data = EntityUtils.toByteArray(entity);
                fileName = DateTool.sysDateByAllFormat1() + RandomTool.getLetterLowerCase(6) + ".png";
                File file = new File(path);
                if(file.exists()){
                    file.mkdir();
                }
                //图片存入磁盘
                FileOutputStream fos = new FileOutputStream(path + fileName);
                fos.write(data);
                fos.close();
            }
        } catch (UnsupportedEncodingException e){
            errorMsg = "请求通信[" + url + "]字符集转换,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ConnectTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时连接超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (SocketTimeoutException e) {
            errorMsg = "请求通信[" + url + "]时读取超时,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ClientProtocolException e) {
            errorMsg = "请求通信[" + url + "]时协议异常,堆栈信息如下:" + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (ParseException e) {
            errorMsg = "请求通信[" + url + "]时解析异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (IOException e) {
            errorMsg = "请求通信[" + url + "]时网络异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } catch (Exception e) {
            errorMsg = "请求通信[" + url + "]时网络异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        } finally {
            //释放资源
            releaseResources(httpResponse, httpPost, errorMsg, url);
        }
        return fileName;
    }




    /**
     * 释放资源
     * @param httpResponse
     * @param object
     * @param errorMsg
     * @param url
     * @throws Exception
     */
    public static  void releaseResources(CloseableHttpResponse httpResponse, Object object, String errorMsg, String url) throws  Exception{
        try {
            if (null != httpResponse){
                httpResponse.close();
            }
            if(null != object){
                if(object instanceof HttpPost){
                    HttpPost httpPost = (HttpPost) object;
                    httpPost.releaseConnection();
                }
                if(object instanceof HttpGet){
                    HttpGet httpGet = (HttpGet) object;
                    httpGet.releaseConnection();
                }
            }
        } catch (IOException e) {
            errorMsg = "请求通信[" + url + "]时资源异常,堆栈信息如下: " + getException(e);
            logger.error(errorMsg);
            throw new Exception(errorMsg);
        }

    }

    /**
     * 获取详细异常信息
     * @param e
     * @return
     */
    public synchronized static String getException(Exception e) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("##########exception【请求异常: 发送请求出现异常】##########");
        buffer.append("\n");
        buffer.append("[getMessage]: ");
        buffer.append("\n\t");
        buffer.append(e.getMessage());
        StackTraceElement[] stackTraceElements = e.getStackTrace();
        if (null != stackTraceElements) {
            buffer.append("\n");
            buffer.append("[getStackTraceElement]: ");
            buffer.append("\n");
            for (StackTraceElement element : stackTraceElements) {
                buffer.append("\t" + element + "\n");
            }
        }
        return buffer.toString();
    }





    public static Map<HttpRoute, PoolStats> getConnManagerStats() {
        if (connManager != null) {
            Set<HttpRoute> routeSet = connManager.getRoutes();
            if (routeSet != null && !routeSet.isEmpty()) {
                Map<HttpRoute, PoolStats> routeStatsMap = new HashMap<HttpRoute, PoolStats>();
                for (HttpRoute route : routeSet) {
                    PoolStats stats = connManager.getStats(route);
                    routeStatsMap.put(route, stats);
                }
                return routeStatsMap;
            }
        }
        return null;
    }



    public static PoolStats getConnManagerTotalStats() {
        if (connManager != null) {
            return connManager.getTotalStats();
        }
        return null;
    }


    /**
     * 关闭系统时关闭httpClient
     */
    public static void releaseHttpClient() {
        try {
            httpClient.close();
        } catch (IOException e) {
            //e.printStackTrace();
            logger.error("关闭httpClient异常" + e);
        } finally {
            if (connManager != null) {
                connManager.shutdown();
            }
        }
    }


    /**
     * 获取HttpClient
     * @return
     */
    private static CloseableHttpClient getHttpClient() {
        return HttpClients.custom().setConnectionManager(connManager).build();
    }

}